package util.http;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.routing.HttpRoutePlanner;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.conn.SystemDefaultRoutePlanner;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;

import javax.net.ssl.*;
import java.io.IOException;
import java.net.ProxySelector;
import java.nio.charset.Charset;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 发送请求工具类 copy from dajia HttpClientUtil
 *
 * @author: Anc
 * @date: 2022/7/01
 */
@Slf4j
public class HttpClientUtil {
    private static SystemDefaultRoutePlanner ROUTE_PLANNER = null;
    private static HostnameVerifier VERIFIER = null;
    private static PoolingHttpClientConnectionManager CM = null;
    private static final int CONNECTION_TIMEOUT_MILLS = 60000;
    private static final int SOCKET_TIMEOUT_MILLS = 60000;
    private static final int MAX_CONNECTIONS = 200;
    private static final int MAX_CONNECTIONS_PER_ROUTE = 20;
    private static final int IDLE_TIMEOUT_SECOND = 30;


    public static CloseableHttpClient getHttpClient() {
        return getHttpClient(SOCKET_TIMEOUT_MILLS, CONNECTION_TIMEOUT_MILLS);
    }

    public static CloseableHttpClient getIgnoreSSLHttpClient() {
        return getIgnoreSSLHttpClient(SOCKET_TIMEOUT_MILLS, CONNECTION_TIMEOUT_MILLS);
    }

    public static CloseableHttpClient getHttpClient(int socketTimeoutMills, int connectTimeoutMills) {
        return getHttpClient(defaultRoutePlanner(), timeoutRequestConfig(socketTimeoutMills, connectTimeoutMills),
            new DefaultHostnameVerifier());
    }

    public static CloseableHttpClient getIgnoreSSLHttpClient(int socketTimeoutMills, int connectTimeoutMills) {
        return getHttpClient(defaultRoutePlanner(), timeoutRequestConfig(socketTimeoutMills, connectTimeoutMills),
            ignoreSSL());
    }

    public static CloseableHttpClient getHttpClient(HttpRoutePlanner route, RequestConfig requestConfig,
        HostnameVerifier verifier) {
        HttpClientBuilder builder = HttpClients.custom();
        builder.setConnectionManager(defaultCM(verifier));
        if (route != null) {
            builder.setRoutePlanner(route);
        }

        if (requestConfig != null) {
            builder.setDefaultRequestConfig(requestConfig);
        }

        if (verifier != null) {
            builder.setSSLHostnameVerifier(verifier);
        }

        builder.setConnectionManagerShared(true);
        return builder.build();
    }

    public static <T> T handle(HttpClient httpClient, HttpUriRequest req, ResponseHandler<T> handler) throws Exception {
        T result;
        long start = System.currentTimeMillis();

        try {
            result = httpClient.execute(req, handler);
        } catch (IOException var12) {
            log.error("IO Exception! [" + req.getMethod() + "] URL [" + req.getURI()
                .toString() + "]" +
                var12.getMessage());
            throw var12;
        } finally {
            long end = System.currentTimeMillis();
            if (log.isDebugEnabled()) {
                log.debug("[" + req.getMethod() + "] URL [" + req.getURI()
                    .toString() + "] cost " + (end - start) + " ms.");
            }

        }

        return result;
    }

    public static <T> T handleWithoutVerifySSL(HttpUriRequest req, ResponseHandler<T> handler) throws Exception {
        T result = null;
        CloseableHttpClient client = getIgnoreSSLHttpClient();

        try {
            result = handle(client, req, handler);
        } finally {
            close(client);
        }

        return result;
    }

    public static <T> T handleWithVerifySSL(HttpUriRequest req, ResponseHandler<T> handler) throws Exception {
        T result = null;
        CloseableHttpClient client = getHttpClient();

        try {
            result = handle(client, req, handler);
        } finally {
            close(client);
        }

        return result;
    }

    public static void close(HttpClient httpClient) {
        HttpClientUtils.closeQuietly(httpClient);
    }

    public static String doGet(String url) throws Exception {
        return doGet(url, new HashMap(), new HashMap(), SOCKET_TIMEOUT_MILLS, CONNECTION_TIMEOUT_MILLS);
    }

    public static String doGet(String url, int socketTimeoutMills, int connectTimeoutMills) throws Exception {
        return doGet(url, new HashMap(), new HashMap(), socketTimeoutMills, connectTimeoutMills);
    }

    public static String doGet(String url, Map<String, String> paras) throws Exception {
        return doGet(url, new HashMap(), paras);
    }

    public static String doGet(String url, Map<String, String> paras, int socketTimeoutMills, int connectTimeoutMills)
        throws Exception {
        return doGet(url, new HashMap(), paras, socketTimeoutMills, connectTimeoutMills);
    }

    public static String doGet(String url, Map<String, String> headers, Map<String, String> paras) throws Exception {
        return doGet(url, headers, paras, Consts.UTF_8);
    }

    public static String doGet(String url, Map<String, String> headers, Map<String, String> paras,
        int socketTimeoutMills, int connectTimeoutMills) throws Exception {
        return doGet(url, headers, paras, Consts.UTF_8, socketTimeoutMills, connectTimeoutMills);
    }

    public static String doGet(String url, Map<String, String> headers, Map<String, String> paras, Charset charset)
        throws Exception {
        return doGet(url, headers, paras, charset, SOCKET_TIMEOUT_MILLS, CONNECTION_TIMEOUT_MILLS);
    }

    public static String doGet(String url, Map<String, String> headers, Map<String, String> paras, Charset charset,
        int socketTimeoutMills, int connectTimeoutMills) throws Exception {
        String _url = (new URIBuilder(url)).setCharset(charset)
            .addParameters(formMap(paras))
            .build()
            .toString();
        HttpGet req = new HttpGet(_url);
        Iterator var8 = headers.keySet()
            .iterator();

        while (var8.hasNext()) {
            String k = (String)var8.next();
            req.setHeader(k, (String)headers.get(k));
        }

        return (String)handle(getIgnoreSSLHttpClient(socketTimeoutMills, connectTimeoutMills), req,
            new StringResponseHandler());
    }

    public static String doFormPost(String url, Map<String, String> paras) throws Exception {
        return doFormPost(url, new HashMap(), paras, SOCKET_TIMEOUT_MILLS, CONNECTION_TIMEOUT_MILLS);
    }

    public static String doFormPost(String url, Map<String, String> paras, int socketTimeoutMills,
        int connectTimeoutMills) throws Exception {
        return doFormPost(url, new HashMap(), paras, socketTimeoutMills, connectTimeoutMills);
    }

    public static String doFormPost(String url, Map<String, String> headers, Map<String, String> paras)
        throws Exception {
        return doFormPost(url, headers, paras, Consts.UTF_8, SOCKET_TIMEOUT_MILLS, CONNECTION_TIMEOUT_MILLS);
    }

    public static String doFormPost(String url, Map<String, String> headers, Map<String, String> paras,
        int socketTimeoutMills, int connectTimeoutMills) throws Exception {
        return doFormPost(url, headers, paras, Consts.UTF_8, socketTimeoutMills, connectTimeoutMills);
    }

    public static String doFormPost(String url, Map<String, String> headers, Map<String, String> paras, Charset charset)
        throws Exception {
        return doFormPost(url, headers, paras, charset, SOCKET_TIMEOUT_MILLS, CONNECTION_TIMEOUT_MILLS);
    }

    public static String doFormPost(String url, Map<String, String> headers, Map<String, String> paras, Charset charset,
        int socketTimeoutMills, int connectTimeoutMills) throws Exception {
        HttpEntity entity = new UrlEncodedFormEntity(formMap(paras), charset);
        HttpPost post = new HttpPost(url);
        Iterator var8 = headers.keySet()
            .iterator();

        while (var8.hasNext()) {
            String k = (String)var8.next();
            post.setHeader(k, (String)headers.get(k));
        }

        post.setEntity(entity);
        return (String)handle(getIgnoreSSLHttpClient(socketTimeoutMills, connectTimeoutMills), post,
            new StringResponseHandler());
    }

    public static String doPost(String url, String httpEntity) throws Exception {
        return doPost(url, new HashMap(), httpEntity, SOCKET_TIMEOUT_MILLS, CONNECTION_TIMEOUT_MILLS);
    }

    public static String doPost(String url, String httpEntity, int socketTimeoutMills, int connectTimeoutMills)
        throws Exception {
        return doPost(url, new HashMap(), httpEntity, socketTimeoutMills, connectTimeoutMills);
    }

    public static String doPost(String url, Map<String, String> headers, String httpEntity) throws Exception {
        return doPost(url, headers, httpEntity, "UTF-8", SOCKET_TIMEOUT_MILLS, CONNECTION_TIMEOUT_MILLS);
    }

    public static String doPost(String url, Map<String, String> headers, String httpEntity, int socketTimeoutMills,
        int connectTimeoutMills) throws Exception {
        return doPost(url, headers, httpEntity, "UTF-8", socketTimeoutMills, connectTimeoutMills);
    }

    public static String doPost(String url, Map<String, String> headers, String httpEntity, String charset)
        throws Exception {
        return doPost(url, headers, httpEntity, charset, SOCKET_TIMEOUT_MILLS, CONNECTION_TIMEOUT_MILLS);
    }

    public static String doPost(String url, Map<String, String> headers, String httpEntity, String charset,
        int socketTimeoutMills, int connectTimeoutMills) throws Exception {
        HttpPost post = new HttpPost(url);
        Iterator var7 = headers.keySet()
            .iterator();

        while (var7.hasNext()) {
            String k = (String)var7.next();
            post.setHeader(k, (String)headers.get(k));
        }

        post.setEntity(new StringEntity(httpEntity, charset));
        return (String)handle(getIgnoreSSLHttpClient(socketTimeoutMills, connectTimeoutMills), post,
            new StringResponseHandler());
    }

    public static String doJsonPost(String url, String json) throws Exception {
        return doJsonPost(url, new HashMap(), json, SOCKET_TIMEOUT_MILLS, CONNECTION_TIMEOUT_MILLS);
    }

    public static String doJsonPost(String url, String json, int socketTimeoutMills, int connectTimeoutMills)
        throws Exception {
        return doJsonPost(url, new HashMap(), json, socketTimeoutMills, connectTimeoutMills);
    }

    public static String doJsonPost(String url, Map<String, String> headers, String json) throws Exception {
        return doJsonPost(url, headers, json, SOCKET_TIMEOUT_MILLS, CONNECTION_TIMEOUT_MILLS);
    }

    public static String doJsonPost(String url, Map<String, String> headers, String json, int socketTimeoutMills,
        int connectTimeoutMills) throws Exception {
        Map<String, String> _headers = new HashMap();
        _headers.put("Content-Type", "application/json");
        _headers.putAll(headers);
        HttpPost post = new HttpPost(url);
        Iterator var7 = _headers.keySet()
            .iterator();

        while (var7.hasNext()) {
            String k = (String)var7.next();
            post.setHeader(k, (String)_headers.get(k));
        }

        post.setEntity(new StringEntity(json, "UTF-8"));
        return (String)handle(getIgnoreSSLHttpClient(socketTimeoutMills, connectTimeoutMills), post,
            new StringResponseHandler());
    }

    public static String doPut(String url) throws Exception {
        return doPut(url, new HashMap(), SOCKET_TIMEOUT_MILLS, CONNECTION_TIMEOUT_MILLS);
    }

    public static String doPut(String url, int socketTimeoutMills, int connectTimeoutMills) throws Exception {
        return doPut(url, new HashMap(), socketTimeoutMills, connectTimeoutMills);
    }

    public static String doPut(String url, Map<String, String> params) throws Exception {
        return doPut(url, new HashMap(), (Map)params, SOCKET_TIMEOUT_MILLS, CONNECTION_TIMEOUT_MILLS);
    }

    public static String doPut(String url, Map<String, String> params, int socketTimeoutMills, int connectTimeoutMills)
        throws Exception {
        return doPut(url, new HashMap(), (Map)params, socketTimeoutMills, connectTimeoutMills);
    }

    public static String doPut(String url, Map<String, String> headers, Map<String, String> params) throws Exception {
        List<NameValuePair> pairs = null;
        if (params != null) {
            pairs = (List)params.entrySet()
                .stream()
                .map((entry) -> {
                    return new BasicNameValuePair((String)entry.getKey(), (String)entry.getValue());
                })
                .collect(Collectors.toList());
        }

        return doPut(url, headers, (List)pairs, SOCKET_TIMEOUT_MILLS, CONNECTION_TIMEOUT_MILLS);
    }

    public static String doPut(String url, Map<String, String> headers, Map<String, String> params,
        int socketTimeoutMills, int connectTimeoutMills) throws Exception {
        List<NameValuePair> pairs = null;
        if (params != null) {
            pairs = (List)params.entrySet()
                .stream()
                .map((entry) -> {
                    return new BasicNameValuePair((String)entry.getKey(), (String)entry.getValue());
                })
                .collect(Collectors.toList());
        }

        return doPut(url, headers, pairs, socketTimeoutMills, connectTimeoutMills);
    }

    public static String doPut(String url, Map<String, String> headers, List<NameValuePair> pairs) throws Exception {
        return doPut(url, headers, (List)pairs, SOCKET_TIMEOUT_MILLS, CONNECTION_TIMEOUT_MILLS);
    }

    public static String doPut(String url, Map<String, String> headers, List<NameValuePair> pairs,
        int socketTimeoutMills, int connectTimeoutMills) throws Exception {
        HttpPut put = new HttpPut(url);
        if (headers != null) {
            Iterator var6 = headers.keySet()
                .iterator();

            while (var6.hasNext()) {
                String k = (String)var6.next();
                put.setHeader(k, (String)headers.get(k));
            }
        }

        if (pairs != null) {
            put.setEntity(new UrlEncodedFormEntity(pairs, "UTF-8"));
        }

        return (String)handle(getIgnoreSSLHttpClient(socketTimeoutMills, connectTimeoutMills), put,
            new StringResponseHandler());
    }

    public static String doJsonPut(String url) throws Exception {
        return doJsonPut(url, new HashMap(), (String)null, SOCKET_TIMEOUT_MILLS, CONNECTION_TIMEOUT_MILLS);
    }

    public static String doJsonPut(String url, int socketTimeoutMills, int connectTimeoutMills) throws Exception {
        return doJsonPut(url, new HashMap(), (String)null, socketTimeoutMills, connectTimeoutMills);
    }

    public static String doJsonPut(String url, String json) throws Exception {
        return doJsonPut(url, new HashMap(), json, SOCKET_TIMEOUT_MILLS, CONNECTION_TIMEOUT_MILLS);
    }

    public static String doJsonPut(String url, String json, int socketTimeoutMills, int connectTimeoutMills)
        throws Exception {
        return doJsonPut(url, new HashMap(), json, socketTimeoutMills, connectTimeoutMills);
    }

    public static String doJsonPut(String url, Map<String, String> headers, String json) throws Exception {
        return doJsonPut(url, headers, json, SOCKET_TIMEOUT_MILLS, CONNECTION_TIMEOUT_MILLS);
    }

    public static String doJsonPut(String url, Map<String, String> headers, String json, int socketTimeoutMills,
        int connectTimeoutMills) throws Exception {
        HttpPut put = new HttpPut(url);
        if (headers != null) {
            Iterator var6 = headers.keySet()
                .iterator();

            while (var6.hasNext()) {
                String k = (String)var6.next();
                put.setHeader(k, (String)headers.get(k));
            }
        }

        put.setHeader("Content-Type", "application/json");
        if (json != null && json.length() > 0) {
            put.setEntity(new StringEntity(json, "UTF-8"));
        }

        return (String)handle(getIgnoreSSLHttpClient(socketTimeoutMills, connectTimeoutMills), put, new
            StringResponseHandler());
    }

    public static PoolingHttpClientConnectionManager defaultCM(HostnameVerifier verifier) {
        if (CM == null) {
            SSLContext sslContext = getSSLContext(verifier);
            SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory(sslContext, verifier);
            RegistryBuilder<ConnectionSocketFactory> schemeRegistry = RegistryBuilder.create();
            Registry<ConnectionSocketFactory> socketFactoryRegistry = schemeRegistry.register("http",
                PlainConnectionSocketFactory.getSocketFactory())
                .register("https", sslConnectionFactory)
                .build();
            CM = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            CM.setMaxTotal(MAX_CONNECTIONS);
            CM.setDefaultMaxPerRoute(MAX_CONNECTIONS_PER_ROUTE);
            CM.closeIdleConnections(IDLE_TIMEOUT_SECOND, TimeUnit.SECONDS);
        }

        return CM;
    }

    public static SSLContext getSSLContext(HostnameVerifier verifier) {
        SSLContext ctx;
        if (NoopHostnameVerifier.INSTANCE.equals(verifier)) {
            try {
                ctx = SSLContext.getInstance("TLS");
                X509TrustManager tm = new X509TrustManager() {
                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }

                    @Override
                    public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                    }
                };
                ctx.init((KeyManager[])null, new TrustManager[] {tm}, (SecureRandom)null);
                return ctx;
            } catch (Exception var3) {
                log.error("", var3);
            }
        }

        ctx = SSLContexts.createDefault();
        return ctx;
    }

    public static RequestConfig defaultRequestConfig() {
        return RequestConfig.custom()
            .setSocketTimeout(SOCKET_TIMEOUT_MILLS)
            .setConnectTimeout(CONNECTION_TIMEOUT_MILLS)
            .build();
    }

    public static RequestConfig timeoutRequestConfig(int socketTimeoutMills, int connectTimeoutMills) {
        return RequestConfig.custom()
            .setSocketTimeout(socketTimeoutMills)
            .setConnectTimeout(connectTimeoutMills)
            .build();
    }

    public static HostnameVerifier ignoreSSL() {
        if (VERIFIER == null) {
            VERIFIER = NoopHostnameVerifier.INSTANCE;
        }

        return VERIFIER;
    }

    public static HttpRoutePlanner defaultRoutePlanner() {
        if (ROUTE_PLANNER == null) {
            ROUTE_PLANNER = new SystemDefaultRoutePlannerExt(ProxySelector.getDefault());
        }

        return ROUTE_PLANNER;
    }

    public static List<NameValuePair> formMap(Map<String, String> map) {
        List<NameValuePair> nameValuePairs = new ArrayList();
        Iterator var2 = map.keySet()
            .iterator();

        while (var2.hasNext()) {
            String k = (String)var2.next();
            nameValuePairs.add(new BasicNameValuePair(k, (String)map.get(k)));
        }

        return nameValuePairs;
    }
}
